package shiro;

import com.alibaba.fastjson.JSON;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * @author lzh
 * @description
 * @date 2021/2/12
 */
public class JwtFilter extends BasicHttpAuthenticationFilter {
    private static final Logger log = LoggerFactory.getLogger(JwtFilter.class);
    private static final String HEADER = "Authorization";
    private static final String PARAM = "token";
    private AntPathMatcher pathMatcher = new AntPathMatcher();


    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {

        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        // 放行不应该被拦截的url
        String[] anonUrls = {"/api/login"};
        boolean match = false;
        String tmp = httpServletRequest.getRequestURI();
        for (String u : anonUrls) {
            if (pathMatcher.match(u, tmp)) {
                match = true;
                break;
            }
        }

        if (match) return true;
//        如果是携带token的请求，则执行token登录操作，有可能token已经失效或者token非法，此时返回false，否则返回true
        if (isLoginAttempt(request, response)) {
            try {
                return executeLogin(request, response);
            } catch (Exception e) {
               writeJSON(response, R.fail(401, e.getMessage()));
               return false;
            }
        }
        return true;
//        writeJSON(response, R.fail(401, "请先登录"));
//        return false;
//        return super.isAccessAllowed(request, response, mappedValue);
    }

    private void writeJSON(ServletResponse response, R result) {
        String jsonStr = JSON.toJSONString(result);
        response.setContentType("application/json;charset=utf-8");
        try(PrintWriter writer = response.getWriter()) {
            writer.write(jsonStr);
            writer.flush();
        } catch (IOException ioException) {
            ioException.printStackTrace();
        }
    }
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
//        return true以便发现404not found的异常
        return true;
    }

    /**
     * 判断该url请求是否携带了token，如果携带了，则可以认为这是一个登录请求，需要执行登录操作，token可以从请求头或者请求参数中获得，如果两处都有token，则优先看请求参数的
     *
     * @param request
     * @param response
     * @return
     */
    @Override
    protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        String token = httpServletRequest.getParameter(PARAM);
        if (token == null) {
            String tmp = httpServletRequest.getHeader(HEADER);
            if (null != tmp) {
                String[] arr = tmp.split(" ");
//                这个需要与前端协调 header['Authorization'] = "token xxxxx"
                if (arr.length == 2 && "token".equals(arr[0])) {
                    token = arr[1];
                }
            }

        }
        return token != null;
//        return super.isLoginAttempt(request, response);
    }

    @Override
    protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        String tokenString = httpServletRequest.getParameter(PARAM);
        if (tokenString == null) {
            tokenString = httpServletRequest.getHeader(HEADER).split(" ")[1];
        }
        if (tokenString == null) {
            throw new IllegalStateException();
        }
        JwtToken token = new JwtToken(tokenString);
        getSubject(request, response).login(token);
        return true;
//        return super.executeLogin(request, response);
    }

    /**
     * 增加跨域的支持,但是跨域可能带来安全隐患
     *
     * @param request
     * @param response
     * @return
     */
    @Override
    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        httpServletResponse.setHeader("Access-Control-Allow-Origin", httpServletRequest.getHeader("Origin"));
        httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"));
        if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
            httpServletResponse.setStatus(HttpStatus.OK.value());
            return false;// option请求不继续向下传递
        } else {
//            正常处理请求
            return super.preHandle(request, response);
        }
    }
}
